package com.leigq.dynamic.task.web.config;

import com.leigq.dynamic.task.web.IDynamicTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;


/**
 * 动态任务配置
 * <br/>
 * 参考：<a href='https://blog.csdn.net/qq_41999204/article/details/114997670'>spring 定时器任务，动态配置 cron表达式并且立即生效，无需重启服务!</a>
 *
 * @author leiguoqing
 */
@Slf4j
@EnableScheduling
@Configuration
public class DynamicTaskConfig implements SchedulingConfigurer, DisposableBean {

    /**
     * Future handles, to cancel the running jobs
     */
    private final Map<String, ScheduledFuture<?>> FUTURE_MAP = new ConcurrentHashMap<>();

    /**
     * 获取 定时任务的具体的类，用于后期 重启，更新等操作
     */
    private final Map<String, IDynamicTask> SERVICE_MAP = new ConcurrentHashMap<>();


    /**
     * 自定义，参考 TriggerTask，为了统一在实现类中，调用 getTrigger() 和 getTask()
     */
    private final Collection<IDynamicTask> scheduledServices;


    /**
     * 句柄，方便后期获取 future
     */
    private TaskScheduler taskScheduler;


    /**
     * spring特性： 初始化该类时，自动获取和装配 项目中 所有的子类 ITriggerTask
     *
     * @param scheduledServices the scheduled services
     */
    public DynamicTaskConfig(Collection<IDynamicTask> scheduledServices) {
        this.scheduledServices = scheduledServices;
    }


    /**
     * Configure tasks.
     *
     * @param taskRegistrar the task registrar
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskScheduler());
        if (null != scheduledServices && scheduledServices.size() > 0) {
            for (final IDynamicTask service : scheduledServices) {
                ScheduledFuture<?> schedule = taskScheduler.schedule(service.getTask(), service.getTrigger());
                FUTURE_MAP.put(service.type(), schedule);
                SERVICE_MAP.put(service.type(), service);
            }
        }
    }


    /**
     * Destroy.
     */
    @Override
    public void destroy() {
        for (ScheduledFuture<?> future : FUTURE_MAP.values()) {
            if (future != null) {
                future.cancel(true);
            }
        }
        FUTURE_MAP.clear();
        SERVICE_MAP.clear();
        ((ThreadPoolTaskScheduler) taskScheduler).destroy();
    }


    /**
     * 线程池任务调度器
     * <p>
     * 支持注解方式，@Scheduled(cron = "0/5 * * * * ?")
     *
     * @return the task scheduler
     */
    @Bean("dynamicTaskScheduler")
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1);
        scheduler.setThreadNamePrefix("DynamicTaskScheduler-");
        // 保证能立刻丢弃运行中的任务
        scheduler.setRemoveOnCancelPolicy(true);
        // 获取 句柄，方便后期获取 future
        taskScheduler = scheduler;
        return scheduler;
    }


    /**
     * Gets future map.
     *
     * @return the future map
     */
    public Map<String, ScheduledFuture<?>> getFutureMap() {
        return FUTURE_MAP;
    }

    /**
     * Gets service map.
     *
     * @return the service map
     */
    public Map<String, IDynamicTask> getServiceMap() {
        return SERVICE_MAP;
    }
}

